﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Animation;
using BaseControls;
using Engine;
using HOG.Behaviors;
using System.Windows.Media.Imaging;

namespace HOG.Controls
{
    public partial class FrameControl : UserControl, IHudGameInterface, IEngineInterface
    {
        #region Constructor.

        public FrameControl()
        {
            InitializeComponent();
            Player p = new Player() { Id = 0, Name = "Michał", Points = 0, TimePlay = 0 };
            game = new Game(p, "HOG;component/MainScenario.xml");//@"C:\Users\Bartek\Csharp\HOG\Project\HOG\HOG\MainScenario.xml");//"HOG;component/MainScenario.xml");
            game.LevelReady += new LevelReadyDelegate(LevelReady);
            game.StartLoadingLevel += new StartConstructingDelegate(StartLoadingLevel);
            game.GameEvent += new BaseControls.GameEventHandler(OnGameEvent);
            game.LoadingChange += new ProgressChangeDelegate(LoadingChange);
            //initialize main menu control
            menu = new MainMenu();

            //disabling/enabling exit button
            if (!(App.Current.IsRunningOutOfBrowser))
                menu.ExitGameButton.Visibility = Visibility.Collapsed;
            else
                menu.ExitGameButton.Visibility = Visibility.Visible;
            RootControl.Children.Add(menu);

            hud = new Hud();
            //hud.GameOptions.Click += new RoutedEventHandler(GameOptions_Click);            
            RootControl.Children.Add(hud);

            Storyboard.SetTarget(InterfaceClose, hud.Interface);
            Storyboard.SetTarget(InterfaceShow, hud.Interface);
            Storyboard.SetTarget(MainMenuShow, menu);
            Storyboard.SetTarget(MainMenuClose, menu);

            HideInterface();

            ShowMainMenu();
        }

        #endregion

        #region Fields.

        /// <summary>
        /// Game engine object.
        /// </summary>
        private Game game;
        private MainMenu menu;
        private Hud hud;
        /// <summary>
        /// Used when scene are downloading.
        /// </summary>
        private WaitControl waitControl;

        #endregion

        #region Game events.

        #region Loading Levels

        //time line for Loding levels
        //FrameControl->(Event)Start Game->StartLoadingLevel->LoadingChange->Level Ready 

        /// <summary>
        /// This event is invoke after download scene xaml and resources like video, images etc. 
        /// </summary>
        /// <param name="LevelControl">Controls what has been download and dynamic build</param>
        /// <param name="time">How many times have player for game</param>
        void LevelReady(Control LevelControl, int time)
        {
            foreach (FrameworkElement item in RootControl.Children)
                if (item is WaitControl)//Level ready is raise for Waiting controls and Scenes
                {
                    RootControl.Children.Remove(item);
                    break;
                }
            content.Children.Clear();
            if (LevelControl.FindName("MainGameLevel") != null)//if its a level
            {
                ShowInterface();
                content.Children.Add(LevelControl);
                hud.FindList.SetItemsList(game.GetItems());
                game.GetItems();//generate items list
                hud.clock.Time = time;
                hud.clock.Start();
                hud.clock.TimeElapsed += new TimeElapsedDelegate(timeOut);//set the timeout for level
                StopStoryBoard(BlackScreenClose);
                BlackScreenClose.Begin();
            }
            else//if its still
            {
                content.Children.Add(LevelControl);
                StopStoryBoard(BlackScreenShow);
                BlackScreenShow.Begin();
            }
            SceneShow show = new SceneShow();//start animation
            show.Attach(LevelControl);

        }

        /// <summary>
        /// This method is raise before level is loaded. 
        /// </summary>
        /// <param name="count">Count of object that will be downloaded</param>
        void StartLoadingLevel(int count)
        {
            content.Children.Clear();
            waitControl = new WaitControl();
            waitControl.Restart(count);
            RootControl.Children.Add(waitControl);
            StopStoryBoard(BlackScreenShow);
            BlackScreenShow.Begin();

        }
        /// <summary>
        /// This method increment counts of downloaded resources.
        /// </summary>
        void LoadingChange()
        {
            waitControl.ProcessChange();
        }

        #endregion

        #region Levels Events

        /// <summary>
        /// Main game events channel on level.
        /// </summary>
        /// <param name="data">object data</param>
        /// <param name="type">enumeration for information about kind of event</param>
        void OnGameEvent(object data, BaseControls.GameChangeType type)
        {
            switch (type)
            {
                case GameChangeType.ItemComplete: { ItemComplete(data.ToString()); break; }
                case GameChangeType.LevelComplete: { LevelCompleted(data); break; }
            }
        }

        /// <summary>
        /// When user found one element this event is raise.
        /// </summary>
        /// <param name="itemFound">name of object that is founded</param>
        void ItemComplete(string itemFound)
        {
            hud.FindList.ItemFound(itemFound);
        }

        /// <summary>
        /// When user finish level this event is raised.
        /// </summary>
        /// <param name="data">data for object</param>
        /// <param name="handler">events args</param>
        void LevelCompleted(object data)
        {
            content.Children.Clear();
            int time = hud.clock.StopTimer();
            HideInterface();
            if (!(data is BaseStory))//data is a array of int where
            {
                HitScore score = (HitScore)data;
                game.AddPoints(score.goodClick, score.badClick, time);
                StopStoryBoard(BlackScreenClose);
                BlackScreenClose.Begin();
            }
            if (!game.LoadNextLevel())//this is last level || game.LoadNextLevel load next level not just check game scenario and return value
            {
                HitScore score = (HitScore)data;
                game.AddPoints(score.goodClick, score.badClick, time);
                EndGame(game.Player.Points, game.Player.TimePlay);
            }
        }

        /// <summary>
        /// This event is raised when user finished game.
        /// </summary>
        /// <param name="points">points for game</param>
        /// <param name="time">play time</param>
        private void EndGame(int points, int time)
        {
            hud.clock.StopTimer();
            HideInterface();
            content.Children.Clear();
            EndGameControl endGame = new EndGameControl();
            endGame.BackToMainMenu += new EventHandler((obj, arg) =>
            {
                content.Children.Clear();
                game.Player.Points = 0;
                ShowMainMenu();
            });
            endGame.PopulateData(points, time);
            content.Children.Add(endGame);
            StopStoryBoard(BlackScreenShow);
            BlackScreenShow.Begin();
        }

        /// <summary>
        /// This method is raised when user dont finished game in time.
        /// </summary>
        private void timeOut()
        {
            ShowGameOver();
        }

        /// <summary>
        /// This method show GameOver on screen.
        /// </summary>
        private void GameOver()
        {
            game.UpdateMusic(MusicUpdate.stop);
            GameOverControl gameOver = new GameOverControl();
            content.Children.Add(gameOver);
            gameOver.BackToMainMenu += (obj, arg) =>
            {
                content.Children.Clear();
                game.Player.Points = 0;
                ShowMainMenu();
            };
            StopStoryBoard(BlackScreenShow);
            BlackScreenShow.Begin();
        }
        /// <summary>
        /// This method Change state of the game like stop music.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ChangeMusicState(object sender, RoutedEventArgs e)
        {
            Options.Options options = (Options.Options)Application.Current.Resources["CustomOptions"];
            if (options != null)
            {
                if (options.VolumeLevel == 0.0)
                {
                    options.VolumeLevel = 1.0;
                    BitmapImage img = new BitmapImage(new Uri("/HOG;Component/Images/Interface/MusicOn.png", UriKind.RelativeOrAbsolute));
                    music.Source = img;
                    game.UpdateMusic(MusicUpdate.start);
                }
                else
                {
                    options.VolumeLevel = 0.0;
                    BitmapImage img = new BitmapImage(new Uri("/HOG;Component/Images/Interface/MusicOff.png", UriKind.RelativeOrAbsolute));
                    music.Source = img;
                    game.UpdateMusic(MusicUpdate.stop);
                }
            }
        }
        #endregion

        #endregion

        #region Game Animations.

        /// <summary>
        /// Initialize GameOver animation.
        /// </summary>
        private void ShowGameOver()
        {
            GameOver();
            hud.clock.StopTimer();
            HideInterface();
            StopStoryBoard(BlackScreenShow);
            BlackScreenShow.Begin();
        }

        /// <summary>
        /// Initialize HUD Interface like clock, object list etc.
        /// </summary>
        private void ShowInterface()
        {
            StopStoryBoard(InterfaceShow);
            InterfaceShow.Begin();
            PauseBehavior.canPause = true;
        }

        private void HideInterface()
        {
            StopStoryBoard(InterfaceClose);
            InterfaceClose.Begin();
            PauseBehavior.canPause = false;
        }

        /// <summary>
        /// Method prevent starting animation twice in this same time.
        /// </summary>
        private void StopStoryBoard(Storyboard board)
        {
            if (board.GetCurrentState() != ClockState.Stopped)
                board.Stop();
        }

        /// <summary>
        /// Initialize Main Menu animation.
        /// </summary>
        private void ShowMainMenu()
        {
            StopStoryBoard(BlackScreenShow);
            BlackScreenShow.Begin();
            StopStoryBoard(MainMenuShow);
            MainMenuShow.Begin();
        }

        private void HideMainMenu()
        {
            StopStoryBoard(BlackScreenClose);
            BlackScreenClose.Begin();
            StopStoryBoard(MainMenuClose);
            MainMenuClose.Begin();
        }

        private void HideGameOver()
        {
            content.Children.Clear();
        }

        #endregion

        #region IHudGameInterface & IGameEngineInterface Members.

        /// <summary>
        /// This method is invoke in Controls and Triggers who can get FrameControl from xaml and need to work Clock object
        /// </summary>
        /// <returns>Clock object</returns>
        Clock IHudGameInterface.GetClock()
        {
            return hud == null && hud.clock == null ? null : hud.clock;
        }

        /// <summary>
        /// This method is invoke in Controls and Triggers who can get FrameControl from xaml and need to work Game object
        /// </summary>
        /// <returns>Game object</returns>
        Game IEngineInterface.GetGame()
        {
            return game;
        }

        /// <summary>
        /// Method invoked by MenuCommandCollection.
        /// </summary>
        void IEngineInterface.StartGame()
        {
            game.Player = new Player() { Id = 0, Name = "Michał", Points = 0, TimePlay = 0 };
            HideMainMenu();
            HideGameOver();
        }

        /// <summary>
        /// Method invoked by MenuCommandCollection.
        /// </summary>
        void IEngineInterface.LoadGame()
        {
            HideMainMenu();
            HideGameOver();
        }

        /// <summary>
        /// Method invoked by MenuCommandCollection.
        /// </summary>
        void IEngineInterface.LoadCredits()
        {
            HideMainMenu();
            HideGameOver();
            CreditsControl credits = new CreditsControl();
            credits.CloseForm.Click += new RoutedEventHandler((obj, ev) =>
            {
                RootControl.Children.Remove(credits);
                ShowMainMenu();
            });
            RootControl.Children.Add(credits);
        }

        /// <summary>
        /// Method invoked by MenuCommandCollection.
        /// </summary>
        void IEngineInterface.LoadLanguageSelect()
        {
            HideMainMenu();
            HideGameOver();
            LanguageControl langControl = new LanguageControl();
            langControl.Close += new EventHandler((obj, ev) =>
            {
                RootControl.Children.Remove(langControl);
                ((MainPage)Application.Current.RootVisual).InitGame();
            });
            RootControl.Children.Add(langControl);
        }

        #endregion
    }
}
